package lmscript.postscript.syntax.stack;

import java.lang.reflect.Field;

import lmscript.postscript.NamedObjectLookup;
import lmscript.postscript.syntax.ArithmeticOperator;
import lmscript.postscript.syntax.ArrayOperator;
import lmscript.postscript.syntax.ControlOperator;
import lmscript.postscript.syntax.ConversionOperator;
import lmscript.postscript.syntax.DeviceOperator;
import lmscript.postscript.syntax.DictionaryOperator;
import lmscript.postscript.syntax.ErrorOperator;
import lmscript.postscript.syntax.FileOperator;
import lmscript.postscript.syntax.GlyphOperator;
import lmscript.postscript.syntax.GraphicsStateDeviceDependentOperators;
import lmscript.postscript.syntax.GraphicsStateOperator;
import lmscript.postscript.syntax.InsidenessTestingOperator;
import lmscript.postscript.syntax.InterpreterOperator;
import lmscript.postscript.syntax.MatrixOperator;
import lmscript.postscript.syntax.MiscellaneousOperator;
import lmscript.postscript.syntax.PSDictionary;
import lmscript.postscript.syntax.PSObject;
import lmscript.postscript.syntax.PackedArrayOperator;
import lmscript.postscript.syntax.PaintingOperator;
import lmscript.postscript.syntax.PathConstructionOperator;
import lmscript.postscript.syntax.PatternOperator;
import lmscript.postscript.syntax.PolymorphicOperator;
import lmscript.postscript.syntax.RelationalOperator;
import lmscript.postscript.syntax.ResourceOperator;
import lmscript.postscript.syntax.StackOperator;
import lmscript.postscript.syntax.StringOperator;
import lmscript.postscript.syntax.VirtualMemoryOperator;

public class DictionaryStack extends PSStack implements NamedObjectLookup {

	public Class[] operators = new Class[] { ArithmeticOperator.class, ArrayOperator.class,
			ControlOperator.class, ConversionOperator.class, DeviceOperator.class,
			DictionaryOperator.class, ErrorOperator.class, FileOperator.class, GlyphOperator.class,
			GraphicsStateDeviceDependentOperators.class, GraphicsStateOperator.class,
			InsidenessTestingOperator.class, InterpreterOperator.class, MatrixOperator.class,
			MiscellaneousOperator.class, PackedArrayOperator.class, PaintingOperator.class,
			PathConstructionOperator.class, PatternOperator.class, PolymorphicOperator.class,
			RelationalOperator.class, ResourceOperator.class, StackOperator.class,
			StringOperator.class, VirtualMemoryOperator.class };

	public static final String SYSTEM_DICT = "systemdict";
	private PSDictionary systemDict = new PSDictionary(SYSTEM_DICT);

	public static final String GLOBAL_DICT = "globaldict";
	private PSDictionary globalDict = new PSDictionary(GLOBAL_DICT);

	public static final String USER_DICT = "userdict";
	private PSDictionary userDict = new PSDictionary(USER_DICT);

	public DictionaryStack() {
		super();

		initSystemDict();
		this.push(systemDict);

		initGlobalDict();
		this.push(globalDict);

		initUserDict();
		this.push(userDict);
	}

	private void initSystemDict() {
		for (Class c : operators) {
			try {
				Field f = c.getField("operators");
				Class[] clazes = (Class[]) f.get(null);
				for (Class op : clazes) {
					addOperator(this.systemDict, op);
				}
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	private void initGlobalDict() {

	}

	private void initUserDict() {

	}

	private void addOperator(PSDictionary dict, Class opClaz) {
		try {
			PSObject obj = (PSObject) opClaz.newInstance();
			String key = obj.getName();
			if (dict.containsKey(key)) {
				// system error
			} else {
				dict.put(key, obj);
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public PSDictionary getCurrentDictionary() {
		return (PSDictionary) this.peek();
	}

	public PSDictionary getSystemDict() {
		return this.systemDict;
	}
	
	public PSDictionary getGlobalDict() {
		return this.globalDict;
	}
	
	public PSDictionary getUserDict() {
		return this.userDict;
	}
	
	public PSDictionary findDict(PSObject key) {
		return null;
	}
	
	@Override
	public PSObject lookup(PSObject name) {
		int count = super.count();
		for (int i = 0; i < count; i++) {
			PSDictionary dict = (PSDictionary) super.peek(i);
			if (dict.containsKey(name)) {
				return dict.get(name);
			}
		}
		return null;
	}
}
